﻿using System;
using System.Linq;
using System.Xml;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;

namespace TagChimp
{
    /// <summary>
    /// Creates a new instance of the TagChimp Client Service
    /// </summary>
    /// <remarks></remarks>
    public class TagChimpClient
    {
        /// <summary>
        /// Gets or sets the Tag Chimp API key.
        /// </summary>
        /// <value>The API key.</value>
        /// <remarks></remarks>
        public string ApiKey { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="TagChimpClient"/> class.
        /// </summary>
        /// <param name="apiKey">Your TagChimp API key.</param>
        /// <exception cref="ArgumentException"/>
        /// <remarks></remarks>
        public TagChimpClient(string apiKey)
        {
            if (String.IsNullOrEmpty(apiKey))
                throw new ArgumentException("Api Key is null or empty.", "apiKey");
            ApiKey = apiKey;
        }
        /// <summary>
        /// Initializes a new TagChimp Client instance.
        /// </summary>
        /// <remarks></remarks>
        public TagChimpClient()
        {
            ApiKey = "5952710984D89ACECA4C82";
        }
        /// <summary>
        /// Gets the episode info.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <returns>EpisodeInfo populated from TagChimp webservice</returns>
        /// <exception cref="TagChimpHttpException"/>
        /// <exception cref="TagChimpTitleNotFoundException"/>
        /// <exception cref="TagChimpApiKeyMissing"/>
        /// <exception cref="TagChimpApiKeyInvalid"/>
        /// <remarks></remarks>
        public  EpisodeInfo     getEpisodeInfo(string filename)
        {
            var ei = ParseFilename(filename);
            
            return getEpisodeInfo(ei);
        }
        /// <summary>
        /// Gets the episode info.
        /// </summary>
        /// <param name="ei">The ei.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public EpisodeInfo getEpisodeInfo(EpisodeInfo ei)
        {
            return MapXmlToEpisodeInfo(ei);
        }
        #region Episode Builder
        /// <summary>
        /// Maps the XML from the TagChimp web service to episode info.
        /// </summary>
        /// <param name="ei">The ei.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private EpisodeInfo     MapXmlToEpisodeInfo(EpisodeInfo ei)
        {

            var doc = getXmlFromWebService(ei);



            var movietags = (from q in doc.DocumentElement.ChildNodes.Cast<XmlNode>()
                             select q.SelectSingleNode("/items/movie/movieTags")).FirstOrDefault();


            var info = movietags.SelectSingleNode("info");

            var tvtags = movietags.SelectSingleNode("television");





            


            ei.CoverArt = movietags.SelectSingleNode("coverArtLarge").InnerText; ;
            ei.Description = info.SelectSingleNode("longDescription").InnerText;
            ei.EpisodeName = info.SelectSingleNode("movieTitle").InnerText;
            ei.Genre = info.SelectSingleNode("category").InnerText;
            ei.MediaType = info.SelectSingleNode("kind").InnerText;
            ei.Network = tvtags.SelectSingleNode("network").InnerText;

            foreach (var n in info.SelectSingleNode("directors").ChildNodes)
            {
                ei.Directors.Add(((XmlNode)n).InnerText);
            }
            foreach (var n in info.SelectSingleNode("cast").ChildNodes)
            {
                ei.Cast.Add(((XmlNode)n).InnerText);
            }

            foreach (var n in info.SelectSingleNode("producers").ChildNodes)
            {
                ei.Producers.Add(((XmlNode)n).InnerText);
            }

            ei.Rating = info.SelectSingleNode("rating").InnerText; 
            
            return ei;
        }
        /// <summary>
        /// Parses the episode filename.
        /// </summary>
        /// <param name="filename">The episodes filename.</param>
        /// <exception cref="ArgumentException"/>
        /// <exception cref="FormatException"/>
        /// <returns></returns>
        /// <remarks></remarks>
        private EpisodeInfo     ParseFilename(string filename)
        {
            
            if (String.IsNullOrEmpty(filename))
                throw new ArgumentException("filename is null or empty.", "filename");


            var r = new Regex(@"(([S,s])([0-9])([0-9])([E,e])([0-9])([0-9]))");

            
            var ep = Regex.Split(filename, r.ToString());

            string showname = "no match";
            var season = 0;
            var episode = 0;

            if (r.IsMatch(filename))
            {
                showname = new StringBuilder(ep[0]).Replace('.', ' ').ToString();
                season = Convert.ToInt32(ep[1].Substring(1, 2));
                episode = Convert.ToInt32(ep[1].Substring(4, 2));

            }
            else
            {
                throw new ("Malformed filename. Is this perhaps movie and not a tv show ");
            }



            return new EpisodeInfo
            {
                EpisodeNumber = episode,
                SeasonNumber = season,
                SeriesName = showname
            };

        }
        /// <summary>
        /// Builds the episode query URL.
        /// </summary>
        /// <param name="ei">The ei.</param>
        /// <exception cref="TagChimpApiKeyMissing"/>
        /// <returns>TagChimp television query url</returns>
        /// <remarks></remarks>
        private string          BuildEpisodeQueryUrl(EpisodeInfo ei)
        {
           

            if (String.IsNullOrEmpty(ApiKey))
                throw new TagChimpApiKeyMissing();



            string url = String.Format("http://tagchimp.com/ape/lookup.php?token={0}&show={1}&season={2}&episode={3}&limit=1", 
                             ApiKey, 
                             new StringBuilder( ei.SeriesName.Trim()).Replace(' ', '+'), 
                             ei.SeasonNumber, 
                             ei.EpisodeNumber);

            
            
            return  url;
        }
        /// <summary>
        /// Gets the XML from the TagChimp web service.
        /// </summary>
        /// <param name="ei">EpisodeInfo instance.</param>
        /// <exception cref="TagChimpTitleNotFoundException"/>
        /// <exception cref="TagChimpApiKeyInvalid"/>
        /// <returns></returns>
        /// <remarks></remarks>
        private XmlDocument     getXmlFromWebService(EpisodeInfo ei)
        {

            
            Console.WriteLine("Retrieving Xml..");

            var doc = new XmlDocument();

            

            try
            {
               doc.Load(BuildEpisodeQueryUrl(ei)); 
            }
            catch (WebException)
            {
                throw new TagChimpHttpException();
            }





            if (String.Compare(doc.DocumentElement.InnerText, "title not found", false) == 0)
                                
                throw new TagChimpTitleNotFoundException();

            else if (String.Compare(doc.DocumentElement.InnerText, "a valid token is required", false) == 0)
            {
                throw new TagChimpApiKeyInvalid();
            }
            else
            {

                Console.WriteLine("Data Recieved Successfully!");
                return doc;
            
            }

        }
        #endregion

        #region Movie Builder

        //TODO:  Add Movie Building Logic 
        #endregion



    }


}